package com.abl.common.web;

import com.abl.common.security.annotation.ResM;
import com.abl.common.mybatis.model.Dnt;
import com.abl.common.util.http.RequestKit;
import com.abl.service.system.SysAPIService;
import com.alibaba.fastjson2.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;

/**
 * 重复提交处理器
 */
@Aspect
@Component
public class ReSubmitHandler {
    @Autowired
    private SysAPIService apiService;

    private static final Logger log = LoggerFactory.getLogger(ReSubmitHandler.class);

    /**
     * 排除敏感属性字段
     */
    public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};

    // 配置织入点
    @Pointcut("@annotation(com.abl.common.security.annotation.ResM)")
    public void pointCut() {
    }

    /**
     * 请求完成后拦截
     */
    @AfterReturning(pointcut = "@annotation(api)", returning = "result")
    public void doAfterReturning(JoinPoint point, ResM api, Object result) {
        handleAction(point, api, result, null);
    }

    /**
     * 发生异常时拦截
     */
    @AfterThrowing(value = "@annotation(api)", throwing = "exception")
    public void doAfterThrowing(JoinPoint point, ResM api, Exception exception) {
        handleAction(point, api, null, exception);
    }

    protected void handleAction(JoinPoint point, ResM action, Object result, Exception exception) {
        try {
            System.out.println("----------------------ActionLogHandler------------------------");
            var request = RequestKit.request();
            if (request == null) return;

            //当前请求资源信息
            String requestURI = request.getRequestURI();
            Dnt apiInfo = apiService.info(requestURI);

            //不存在或者未开启
            if (apiInfo == null || "1".equals(apiInfo.getString("open_action_log"))) return;

            log.info(requestURI);
            log.info(JSON.toJSONString(apiInfo));

            //组装数据库操作日志对象
            Dnt logAction = Dnt.create();
            setAnnotationMsg(logAction, point, action, result);
            String className = point.getTarget().getClass().getName();
            String methodName = point.getSignature().getName();
            //异步插入数据库
            System.out.println("异步插入数据库");

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 将注解信息插入到数据对象中
     *
     * @param logAction 数据库对象
     * @param point     切点
     * @param api       注解
     * @param result    返回结果
     * @throws Exception
     */
    public void setAnnotationMsg(Dnt logAction, JoinPoint point, ResM api, Object result) throws Exception {
        // 设置action动作
        // 设置标题
        // 设置操作人类别
        // 是否需要保存request，参数和值
        // 获取参数的信息，传入到数据库中。
        // 是否需要保存response，参数和值
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param logAction 操作日志
     * @throws Exception 异常
     */
//    private void setRequestValue(Dnt logAction, JoinPoint joinPoint) throws Exception {
//        Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
//        if (StringUtils.isNotEmpty(map)) {
//            String params = JSONObject.toJSONString(map, excludePropertyPreFilter());
//            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
//        } else {
//            Object args = joinPoint.getArgs();
//            if (StringUtils.isNotNull(args)) {
//                String params = argsArrayToString(joinPoint.getArgs());
//                operLog.setOperParam(StringUtils.substring(params, 0, 2000));
//            }
//        }
//    }

    /**
     * 忽略敏感属性
     */
//    public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter() {
//        return new SimplePropertyPreFilter().addFilter().addExcludes(EXCLUDE_PROPERTIES);
//    }

    /**
     * 参数拼装
     */
//    private String argsArrayToString(Object[] paramsArray) {
//        String params = "";
//        if (paramsArray != null && paramsArray.length > 0) {
//            for (Object o : paramsArray) {
//                if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
//                    try {
//                        Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter());
//                        params += jsonObj.toString() + " ";
//                    } catch (Exception e) {
//                    }
//                }
//            }
//        }
//        return params.trim();
//    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse || o instanceof BindingResult;
    }
}
